package com.qire.common.widget.animation;

import android.animation.Animator;
import android.animation.TimeInterpolator;
import android.animation.ValueAnimator;
import android.os.Build;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.LinearInterpolator;

import com.qire.common.widget.snackbar.SnackBar;

import androidx.annotation.RestrictTo;
import androidx.annotation.RestrictTo.Scope;
import androidx.core.view.ViewCompat;
import androidx.interpolator.view.animation.FastOutLinearInInterpolator;
import androidx.interpolator.view.animation.FastOutSlowInInterpolator;
import androidx.interpolator.view.animation.LinearOutSlowInInterpolator;

@RestrictTo({Scope.LIBRARY_GROUP})
public class AnimationUtils {
    public static final TimeInterpolator LINEAR_INTERPOLATOR = new LinearInterpolator();
    public static final TimeInterpolator FAST_OUT_SLOW_IN_INTERPOLATOR = new FastOutSlowInInterpolator();
    public static final TimeInterpolator FAST_OUT_LINEAR_IN_INTERPOLATOR = new FastOutLinearInInterpolator();
    public static final TimeInterpolator LINEAR_OUT_SLOW_IN_INTERPOLATOR = new LinearOutSlowInInterpolator();
    public static final TimeInterpolator DECELERATE_INTERPOLATOR = new DecelerateInterpolator();

    public static final SnackBar.SceneAnimate snackBarBottomAnimation = new SnackBarBottomAnimation();
    public static final SnackBar.SceneAnimate snackBarTopAnimation = new SnackBarTopAnimation();

    public AnimationUtils() {
    }

    public static float lerp(float startValue, float endValue, float fraction) {
        return startValue + fraction * (endValue - startValue);
    }

    public static int lerp(int startValue, int endValue, float fraction) {
        return startValue + Math.round(fraction * (float)(endValue - startValue));
    }

    /**
     * SnackBar底部推出场景动画
     */
    private static class SnackBarBottomAnimation implements SnackBar.SceneAnimate {

        private static final boolean USE_OFFSET_API = Build.VERSION.SDK_INT >= 16 && Build.VERSION.SDK_INT <= 19;

        private int getTranslationYBottom(View view) {
            int translationY = view.getHeight();
            ViewGroup.LayoutParams layoutParams = view.getLayoutParams();
            if (layoutParams instanceof ViewGroup.MarginLayoutParams) {
                translationY += ((ViewGroup.MarginLayoutParams)layoutParams).bottomMargin;
            }

            return translationY;
        }

        @Override
        public Animator animateViewIn(View view) {
            final int translationYBottom = this.getTranslationYBottom(view);
            if (USE_OFFSET_API) {
                ViewCompat.offsetTopAndBottom(view, translationYBottom);
            } else {
                view.setTranslationY((float)translationYBottom);
            }

            ValueAnimator animator = new ValueAnimator();
            animator.setIntValues(new int[]{translationYBottom, 0});
            animator.setInterpolator(FAST_OUT_SLOW_IN_INTERPOLATOR);

            animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                private int previousAnimatedIntValue = translationYBottom;

                public void onAnimationUpdate(ValueAnimator animator) {
                    int currentAnimatedIntValue = (Integer)animator.getAnimatedValue();
                    if (USE_OFFSET_API) {
                        ViewCompat.offsetTopAndBottom(view, currentAnimatedIntValue - this.previousAnimatedIntValue);
                    } else {
                        view.setTranslationY((float)currentAnimatedIntValue);
                    }

                    this.previousAnimatedIntValue = currentAnimatedIntValue;
                }
            });
            return animator;
        }

        @Override
        public Animator animateViewOut(View view) {
            ValueAnimator animator = new ValueAnimator();
            animator.setIntValues(new int[]{0, this.getTranslationYBottom(view)});
            animator.setInterpolator(FAST_OUT_SLOW_IN_INTERPOLATOR);

            animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                private int previousAnimatedIntValue = 0;

                public void onAnimationUpdate(ValueAnimator animator) {
                    int currentAnimatedIntValue = (Integer)animator.getAnimatedValue();
                    if (USE_OFFSET_API) {
                        ViewCompat.offsetTopAndBottom(view, currentAnimatedIntValue - this.previousAnimatedIntValue);
                    } else {
                        view.setTranslationY((float)currentAnimatedIntValue);
                    }

                    this.previousAnimatedIntValue = currentAnimatedIntValue;
                }
            });

            return animator;
        }
    }

    /**
     * SnackBar顶部滑出场景动画
     */
    private static class SnackBarTopAnimation implements SnackBar.SceneAnimate {

        private static final boolean USE_OFFSET_API = Build.VERSION.SDK_INT >= 16 && Build.VERSION.SDK_INT <= 19;

        private int getTranslationYTop(View view) {
            int translationY = view.getHeight();
            ViewGroup.LayoutParams layoutParams = view.getLayoutParams();
            if (layoutParams instanceof ViewGroup.MarginLayoutParams) {
                translationY += ((ViewGroup.MarginLayoutParams)layoutParams).topMargin;
            }

            return translationY;
        }

        @Override
        public Animator animateViewIn(View view) {
            final int translationYTop = this.getTranslationYTop(view);
            if (USE_OFFSET_API) {
                ViewCompat.offsetTopAndBottom(view, -translationYTop);
            } else {
                view.setTranslationY((float)(-translationYTop));
            }

            ValueAnimator animator = new ValueAnimator();
            animator.setIntValues(new int[]{-translationYTop, 0});
            animator.setInterpolator(FAST_OUT_SLOW_IN_INTERPOLATOR);

            animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                private int previousAnimatedIntValue = 0;

                public void onAnimationUpdate(ValueAnimator animator) {
                    int currentAnimatedIntValue = (Integer)animator.getAnimatedValue();
                    if (USE_OFFSET_API) {
                        ViewCompat.offsetTopAndBottom(view, currentAnimatedIntValue - this.previousAnimatedIntValue);
                    } else {
                        view.setTranslationY((float)currentAnimatedIntValue);
                    }

                    this.previousAnimatedIntValue = currentAnimatedIntValue;
                }
            });

            return animator;
        }

        @Override
        public Animator animateViewOut(View view) {
            final int translationYTop = this.getTranslationYTop(view);
            ValueAnimator animator = new ValueAnimator();
            animator.setIntValues(new int[]{0, -translationYTop});
            animator.setInterpolator(FAST_OUT_SLOW_IN_INTERPOLATOR);

            animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                private int previousAnimatedIntValue = -translationYTop;

                public void onAnimationUpdate(ValueAnimator animator) {
                    int currentAnimatedIntValue = (Integer)animator.getAnimatedValue();
                    if (USE_OFFSET_API) {
                        ViewCompat.offsetTopAndBottom(view, currentAnimatedIntValue - this.previousAnimatedIntValue);
                    } else {
                        view.setTranslationY((float)currentAnimatedIntValue);
                    }

                    this.previousAnimatedIntValue = currentAnimatedIntValue;
                }
            });
            return animator;
        }
    }
}
